﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Wormhole.UI.Application;
using Input = Wormhole.Engine.Input;
using SG1 = Wormhole.Engine.CardLibrary.SG1;

namespace Wormhole.Test.UI.Application
{
	/// <author>Hannes Foulds</author>
	/// <date>17 October 2008</date>
	/// <summary>
	/// While this is not an AI player, it allows for testing of a player that starts of as the hero.
	/// </summary>
	public class HeroPlayer
	{
		#region Declarations
		private int actions = 0;
		#endregion

		#region Properties

		#region Game
		/// <summary>
		/// The game being player
		/// </summary>
		public Engine.Game Game { get; private set; }
		#endregion

		#region Properties
		protected Engine.Player.Player Player1
		{
			get
			{
				return this.Game.Player1;
			}
		}
		#endregion

		#endregion

		#region Constructor
		/// <summary>
		/// Initialize e new instance of the class.
		/// </summary>
		/// <param name="game">The game being played.</param>
		public HeroPlayer()
		{
			this.Game = new Wormhole.Engine.Game();
			this.InitializePlayerDeck(this.Game.Player1);
			this.InitializePlayerDeck(this.Game.Player2);
			this.InitializeEngineEvents();

			this.Game.Connect("localhost", 6667, "Hero_Player");
			this.Game.CreateGame("Hero Player AI");
		}
		#endregion

		#region Initialize Player Deck
		/// <summary>
		/// Initize the card deck for a player.
		/// </summary>
		/// <param name="player">The player to initialize the deck for.</param>
		private void InitializePlayerDeck(Engine.Player.Player player)
		{
			// team
			player.Deck.Add(new SG1.Cards.Hero.Character.SG1C105(player));
			player.Deck.Add(new SG1.Cards.Hero.Character.SG1C88(player));
			player.Deck.Add(new SG1.Cards.Hero.Character.SG1C95(player));
			player.Deck.Add(new SG1.Cards.Hero.Character.SG1S93(player));

			// support characters
			player.Deck.Add(new SG1.Cards.Hero.Character.SG1C66(player));
			player.Deck.Add(new SG1.Cards.Hero.Character.SG1C66(player));
			player.Deck.Add(new SG1.Cards.Hero.Character.SG1C66(player));
			player.Deck.Add(new SG1.Cards.Hero.Character.SG1C65(player));
			player.Deck.Add(new SG1.Cards.Hero.Character.SG1C65(player));
			player.Deck.Add(new SG1.Cards.Hero.Character.SG1C65(player));

			// events
			player.Deck.Add(new SG1.Cards.Hero.Event.SG1C116(player));
			player.Deck.Add(new SG1.Cards.Hero.Event.SG1C116(player));
			player.Deck.Add(new SG1.Cards.Hero.Event.SG1C131(player));
			player.Deck.Add(new SG1.Cards.Hero.Event.SG1C131(player));
			player.Deck.Add(new SG1.Cards.Hero.Event.SG1C131(player));
			player.Deck.Add(new SG1.Cards.Hero.Event.SG1C132(player));
			player.Deck.Add(new SG1.Cards.Hero.Event.SG1C132(player));
			player.Deck.Add(new SG1.Cards.Hero.Event.SG1C132(player));

			// gear
			player.Deck.Add(new SG1.Cards.Hero.Gear.SG1C142(player));
			player.Deck.Add(new SG1.Cards.Hero.Gear.SG1C142(player));
			player.Deck.Add(new SG1.Cards.Hero.Gear.SG1C143(player));
			player.Deck.Add(new SG1.Cards.Hero.Gear.SG1C143(player));
			player.Deck.Add(new SG1.Cards.Hero.Gear.SG1C148(player));
			player.Deck.Add(new SG1.Cards.Hero.Gear.SG1C148(player));

			// missions
			player.Deck.Add(new SG1.Cards.Hero.Mission.SG1S160(player));
			player.Deck.Add(new SG1.Cards.Hero.Mission.SG1S162(player));
			player.Deck.Add(new SG1.Cards.Hero.Mission.SG1S166(player));
			player.Deck.Add(new SG1.Cards.Hero.Mission.SG1S171(player));
			player.Deck.Add(new SG1.Cards.Hero.Mission.SG1S185(player));
			player.Deck.Add(new SG1.Cards.Hero.Mission.SG1S174(player));
			player.Deck.Add(new SG1.Cards.Hero.Mission.SG1S179(player));
			player.Deck.Add(new SG1.Cards.Hero.Mission.SG1S194(player));
			player.Deck.Add(new SG1.Cards.Hero.Mission.SG1S196(player));
			player.Deck.Add(new SG1.Cards.Hero.Mission.SG1S199(player));
			player.Deck.Add(new SG1.Cards.Hero.Mission.SG1S200(player));
			player.Deck.Add(new SG1.Cards.Hero.Mission.SG1S201(player));

			// adversary
			player.Deck.Add(new SG1.Cards.Villain.Adversary.SG1S1(player));
			player.Deck.Add(new SG1.Cards.Villain.Adversary.SG1S1(player));
			player.Deck.Add(new SG1.Cards.Villain.Adversary.SG1C26(player));
			player.Deck.Add(new SG1.Cards.Villain.Adversary.SG1C26(player));

			// obstacle
			player.Deck.Add(new SG1.Cards.Villain.Obstacle.SG1C216(player));
			player.Deck.Add(new SG1.Cards.Villain.Obstacle.SG1C216(player));

			player.Deck.Add(new SG1.Cards.Villain.Obstacle.SG1C231(player));
			player.Deck.Add(new SG1.Cards.Villain.Obstacle.SG1C231(player));
			player.Deck.Add(new SG1.Cards.Villain.Obstacle.SG1C231(player));

			player.Deck.Add(new SG1.Cards.Villain.Obstacle.SG1C239(player));
			player.Deck.Add(new SG1.Cards.Villain.Obstacle.SG1C239(player));

			player.Deck.Add(new SG1.Cards.Villain.Obstacle.SG1C252(player));
			player.Deck.Add(new SG1.Cards.Villain.Obstacle.SG1C252(player));

			player.Deck.Add(new SG1.Cards.Villain.Obstacle.SG1C258(player));
			player.Deck.Add(new SG1.Cards.Villain.Obstacle.SG1C258(player));

			player.Deck.Add(new SG1.Cards.Villain.Obstacle.SG1C276(player));
			player.Deck.Add(new SG1.Cards.Villain.Obstacle.SG1C276(player));
			player.Deck.Add(new SG1.Cards.Villain.Obstacle.SG1C276(player));

			player.Deck.Add(new SG1.Cards.Villain.Obstacle.SG1C278(player));
			player.Deck.Add(new SG1.Cards.Villain.Obstacle.SG1C278(player));
			player.Deck.Add(new SG1.Cards.Villain.Obstacle.SG1C278(player));

			player.Deck.Add(new SG1.Cards.Villain.Obstacle.SG1C281(player));
			player.Deck.Add(new SG1.Cards.Villain.Obstacle.SG1C281(player));
			player.Deck.Add(new SG1.Cards.Villain.Obstacle.SG1C281(player));
		}
		#endregion

		#region Event Handlers

		#region Get Input
		/// <summary>
		/// Handle the event when user input is required.
		/// </summary>
		/// <param name="request"></param>
		private void UserInput_GetInput(Wormhole.Engine.Input.Request request)
		{
			// if a pause is not inserted the sequence of events gets messed up
			System.Threading.Thread.Sleep(500);

			switch (request.ResponseType)
			{
				case Input.ResponseType.YesNo:
					this.HandleYesNo(request);
					break;
				case Input.ResponseType.Pass:
					this.HandlePass(request);
					break;
				case Input.ResponseType.SingleCardSelect:
					this.HandleSingleSelect(request);
					break;
			}
		}
		#endregion

		#region Game Started
		/// <summary>
		/// Handle the game started event.
		/// </summary>
		private void game_GameStarted()
		{
			this.Game.Start();
		}
		#endregion

		#endregion

		#region Initialize Engine Events
		/// <summary>
		/// Wire up the events for the game engine.
		/// </summary>
		protected void InitializeEngineEvents()
		{
			this.Game.GameStarted += new Wormhole.Engine.Game.GameStartedDelegate(game_GameStarted);
			this.Game.Player1.UserInput.GetInput += new Wormhole.Engine.Input.UserInput.GetInputDelegate(UserInput_GetInput);
		}
		#endregion

		#region Disconnect
		/// <summary>
		/// Disconnect from the communications server.
		/// </summary>
		public void Disconnect()
		{
			this.Game.Disconnect();
		}
		#endregion

		private void HandleYesNo(Input.Request request)
		{
			if (this.actions == 0) // take mulligan
			{
				if (this.Game.GameTurn.CurrentPhase == Wormhole.Engine.Turn.Phase.Power)
				{
					this.actions++; // 1
					this.YesNo(false, request);
				}
			}
			else if (this.actions == 5) // play next mission
			{
				if (this.Game.GameTurn.CurrentPhase == Wormhole.Engine.Turn.Phase.DecideContinue)
				{
					this.actions++;
					this.YesNo(true, request);
				}
			}
			else if (this.actions == 11) // play next mission
			{
				if (this.Game.GameTurn.CurrentPhase == Wormhole.Engine.Turn.Phase.DecideContinue)
				{
					this.actions++;
					this.YesNo(false, request);
				}
			}
		}

		#region Handle Pass
		/// <summary>
		/// Handle the pass request.
		/// </summary>
		/// <param name="request"></param>
		private void HandlePass(Input.Request request)
		{
			if (this.Game.GameTurn.CurrentPhase == Wormhole.Engine.Turn.Phase.PerformAction)
			{
				if (this.actions == 1)
				{
					if (this.AssignTeam(3))
						this.actions++;
				}
				else if (this.actions == 2)
				{
					if (this.AssignTeam(2))
						this.actions++;
				}
				else if (this.actions == 3)
				{
					this.actions++;
					this.Pass(request);
				}
				else if (this.actions == 6) // assign character for the second mission
				{
					if (this.AssignTeam(0))
						this.actions++;
				}
				else if (this.actions == 7)
				{
					if (this.AssignTeam(1))
						this.actions++;
				}
				else if (this.actions == 8)
				{
					this.PlayCard(0);
					this.actions++;
				}
				else if (this.actions == 9)
				{
					this.actions++;
					this.Pass(request);
				}
			}
		}
		#endregion

		#region Assign Team
		/// <summary>
		/// Assign a team character to the mission. 
		/// </summary>
		/// <param name="index">The index of the team character.</param>
		/// <returns>Returns true if the character was assigned.</returns>
		private bool AssignTeam(int index)
		{
			Engine.CardLibrary.BaseCardTypes.SkillsCard teamCard = this.Player1.Team[index] as Engine.CardLibrary.BaseCardTypes.SkillsCard;
			if ( this.Player1.HasPriority  && teamCard.CanAssign() )
			{
				teamCard.Assign();
				return true;
			}

			return false;
		}
		#endregion

		#region Play Card
		/// <summary>
		/// Play a card from the hand.
		/// </summary>
		/// <param name="index">The index of the card to play.</param>
		/// <returns>Return true if the card could be played.</returns>
		private bool PlayCard(int index)
		{
			Engine.CardLibrary.BaseCardTypes.Card card = this.Player1.CardsInHand[index];
			if (this.Player1.HasPriority && card.CanPlay())
			{
				card.Play();
				return true;
			}

			return false;
		}
		#endregion

		#region Pass
		/// <summary>
		/// Send a pass message
		/// </summary>
		/// <param name="request"></param>
		private void Pass(Wormhole.Engine.Input.Request request)
		{
			Input.Response response = new Wormhole.Engine.Input.Response();
			response.ResponseType = Wormhole.Engine.Input.ResponseType.Pass;
			request.Callback(response);
		}
		#endregion

		#region YesNo
		/// <summary>
		/// Send a YES Message.
		/// </summary>
		/// <param name="request"></param>
		private void YesNo(bool yes, Wormhole.Engine.Input.Request request)
		{
			Input.Response response = new Wormhole.Engine.Input.Response();
			response.ResponseType = yes ? Wormhole.Engine.Input.ResponseType.Yes : Wormhole.Engine.Input.ResponseType.No;
			request.Callback(response);
		}		
		#endregion

		private void HandleSingleSelect(Wormhole.Engine.Input.Request request)
		{
			if (this.Game.GameTurn.CurrentPhase == Wormhole.Engine.Turn.Phase.ResolveMission)
			{
				if (this.actions == 4) // assign glyph
				{
					this.actions++;

					Input.Response response = new Wormhole.Engine.Input.Response();
					response.ResponseType = Wormhole.Engine.Input.ResponseType.SingleCardSelect;
					response.SelectedCards = new Wormhole.Engine.Decks.Deck();
					response.SelectedCards.Add(this.Player1.Team[3]);

					request.Callback(response);
				}
				if (this.actions == 10) // assign glyph
				{
					this.actions++;

					Input.Response response = new Wormhole.Engine.Input.Response();
					response.ResponseType = Wormhole.Engine.Input.ResponseType.SingleCardSelect;
					response.SelectedCards = new Wormhole.Engine.Decks.Deck();
					response.SelectedCards.Add(this.Player1.Team[0]);

					request.Callback(response);
				}
			}
		}

	}
}
